/*
 * Copyright (C) 2008+ Spark Zheng
 *
 * src/test/test_conf.c
 * 
 * read a config file and the parse each item
 * confloose testing see test_confloose.c
 *
 */

#include <stdio.h>
#include <string.h>

#include "conf.h"

#define CONF_FILE 	"./data/dcache.conf"

#define BASE_DIR	"/home/sparkzheng/Projects/mfs_projects/dcache"
#define CONF_DIR	BASE_DIR"/conf"
#define LOG_DIR		BASE_DIR"/log"
#define BINLOG_DIR	BASE_DIR"/binlog"
#define MF_DIR		BASE_DIR"/mf_data"
#define FACT_DIR	BASE_DIR"/data"
	
/* hashtable lenth */
#define CONF_MAIN_DICT_LEN	31

typedef struct main_setting	S_MAIN_SETTING;

struct main_setting {
	char		*conf_file;	/* config file path */

	uint32_t	max_fds;	/* max filedescripts on dcache */
	uint32_t	max_threads;	/* max threads on dcache */
	
	char		*conf_path;	/* config file path */
	char		*log_path;	/* log file path */
	
	char		*mont_host;	/* monitor host name or ip address */
	uint16_t	mont_port;	/* monitor port for main process */
	uint16_t	mont_timeout;	/* monitor timeout for main process */
	uint16_t	mont_retry;	/* monitor retry times */
	uint16_t	mont_priority;	/* protocol priority for schedule */

	char		*dcomm_conf;	/* dcomm config file */
	char		*protocols;	/* the protocols defined by user */
	
	uint8_t		transaction;	/* switch of transaction */
	char		*binlog_path;	/* path of binlog for transaction */
	
	char		*mf_path;	/* meta factory path */
	uint32_t	mf_cache_size;
	uint32_t	mf_page_size;
	
	char		*factory_path;	/* factory path */
	uint32_t	stripe_size;	/* stripe size */
};

typedef enum {
	MAIN_MAX_FD = 0,	/* 1 */
	MAIN_MAX_THREADS,

	MAIN_CONF_PATH,
	MAIN_LOG_PATH,
	
	MAIN_MONT_HOST,		/* 5 */
	MAIN_MONT_PORT,
	MAIN_MONT_TIMEOUT,
	MAIN_MONT_RETRY,
	MAIN_MONT_PRIORITY,

	MAIN_DCOMM_CONF,	/* 10 */
	MAIN_PROTOCOLS,
	
	MAIN_TRANSACTION,
	MAIN_BINLOG_PATH,
	
	MAIN_MF_PATH,
	MAIN_MF_CACHE_SIZE,	/* 15 */
	MAIN_MF_PAGE_SIZE,

	MAIN_FACTORY_PATH,
	MAIN_STRIPE_SIZE,

	CONF_MAIN_ARGS_NUM	/* 18 */
} CONF_MAIN_ARGS_T;

/* default main conf parameters */
#define VAR_MAX_FD		"max_fds"
#define DEF_MAX_FD		1024U
#define CEIL_MAX_FD		0

#define VAR_MAX_THREADS		"max_threads"
#define DEF_MAX_THREADS		1024U
#define CEIL_MAX_THREADS	0

#define VAR_CONF_PATH		"config_path"
#define DEF_CONF_PATH		CONF_DIR
#define LEN_CONF_PATH		1024U

#define VAR_LOG_PATH		"log_path"
#define DEF_LOG_PATH		LOG_DIR
#define LEN_LOG_PATH		1024U

#define VAR_MONT_HOST		"mont_host"
#define DEF_MONT_HOST		"127.0.0.1"
#define LEN_MONT_HOST		64U

#define VAR_MONT_PORT		"mont_port"
#define DEF_MONT_PORT		10003
#define MAX_MONT_PORT		65535

#define VAR_MONT_TIMEOUT	"mont_timeout"
#define DEF_MONT_TIMEOUT	30U
#define MAX_MONT_TIMEOUT	120U

#define VAR_MONT_RETYR		"mont_retry"
#define DEF_MONT_RETRY		3U
#define MAX_MONT_RETRY		12U

#define VAR_MONT_PRIORITY	"mont_priority"
#define DEF_MONT_PRIORITY	5U
#define MAX_MONT_PRIORITY	20U

#define VAR_DCOMM_CONF		"dcomm_conf"
#define DEF_DCOMM_CONF		"dcomm.conf"
#define LEN_DCOMM_CONF		1024U

#define VAR_PROTOCOLS		"protocols"
#define DEF_PROTOCOLS		"default"
#define LEN_PROTOCOLS		65535U

#define VAR_TRANSACTION		"transaction"
#define DEF_TRANSACTION		"on"
#define LEN_TRANSACTION		4U

#define VAR_BINLOG_PATH		"binlog_path"
#define DEF_BINLOG_PATH		BINLOG_DIR
#define LEN_BINLOG_PATH		1024U

#define VAR_MF_PATH		"mf_path"
#define DEF_MF_PATH		MF_DIR
#define LEN_MF_PATH		1024U

#define VAR_MF_CACHE_SIZE	"mf_cache_size"
#define DEF_MF_CACHE_SIZE	0
#define MAX_MF_CACHE_SIZE	0

#define VAR_MF_PAGE_SIZE	"mf_page_size"
#define DEF_MF_PAGE_SIZE	4096U
#define MAX_MF_PAGE_SIZE	65536U

#define VAR_FACTORY_PATH	"factory_path"
#define DEF_FACTORY_PATH	FACT_DIR
#define LEN_FACTORY_PATH	1024U

#define VAR_STRIPE_SIZE		"stripe_size"
#define DEF_STRIPE_SIZE		4096U
#define MAX_STRIPE_SIZE		(1U << 24)

/* main config file item table */
static dlib_conf_t main_table[CONF_MAIN_ARGS_NUM] = {
	{{VAR_MAX_FD, (char *)DEF_MAX_FD, NULL, 0,
	  CEIL_MAX_FD, MAIN_MAX_FD}},
	{{VAR_MAX_THREADS, (char *)DEF_MAX_THREADS, NULL, 0,
	  CEIL_MAX_THREADS, MAIN_MAX_THREADS}},
	
	{{VAR_CONF_PATH, DEF_CONF_PATH, NULL, 0,
	  LEN_CONF_PATH, MAIN_CONF_PATH}},
	{{VAR_LOG_PATH, DEF_LOG_PATH, NULL, 0,
	  LEN_LOG_PATH, MAIN_LOG_PATH}},
	
	{{VAR_MONT_HOST, DEF_MONT_HOST, NULL, 0,
	  LEN_MONT_HOST, MAIN_MONT_HOST}},
	{{VAR_MONT_PORT, (char *)DEF_MONT_PORT, NULL, 0,
	  MAX_MONT_PORT, MAIN_MONT_PORT}},
	{{VAR_MONT_TIMEOUT, (char *)DEF_MONT_TIMEOUT, NULL, 0,
	  MAX_MONT_TIMEOUT, MAIN_MONT_TIMEOUT}},
	{{VAR_MONT_RETYR, (char *)DEF_MONT_RETRY, NULL, 0,
	  MAX_MONT_RETRY, MAIN_MONT_RETRY}},
	{{VAR_MONT_PRIORITY, (char *)DEF_MONT_PRIORITY, NULL, 0,
	  MAX_MONT_PRIORITY, MAIN_MONT_PRIORITY}},

	{{VAR_DCOMM_CONF, DEF_DCOMM_CONF, NULL, 0,
	  LEN_DCOMM_CONF, MAIN_DCOMM_CONF}},
	{{VAR_PROTOCOLS, DEF_PROTOCOLS, NULL, 0,
	  LEN_PROTOCOLS, MAIN_PROTOCOLS}},

	{{VAR_TRANSACTION, DEF_TRANSACTION, NULL, 0,
	  LEN_TRANSACTION, MAIN_TRANSACTION}},
	{{VAR_BINLOG_PATH, DEF_BINLOG_PATH, NULL, 0,
	  LEN_BINLOG_PATH, MAIN_BINLOG_PATH}},
	
	{{VAR_MF_PATH, DEF_MF_PATH, NULL, 0,
	  LEN_MF_PATH, MAIN_MF_PATH}},
	{{VAR_MF_CACHE_SIZE, (char *)DEF_MF_CACHE_SIZE, NULL, 0,
	  MAX_MF_CACHE_SIZE, MAIN_MF_CACHE_SIZE}},
	{{VAR_MF_PAGE_SIZE, (char *)DEF_MF_PAGE_SIZE, NULL, 0,
	  MAX_MF_PAGE_SIZE, MAIN_MF_PAGE_SIZE}},
	
	{{VAR_FACTORY_PATH, DEF_FACTORY_PATH, NULL, 0,
	  LEN_FACTORY_PATH, MAIN_FACTORY_PATH}},
	{{VAR_STRIPE_SIZE, (char *)DEF_STRIPE_SIZE, NULL, 0,
	  MAX_STRIPE_SIZE, MAIN_STRIPE_SIZE}}
};

static void _main_conf_set_setting(S_MAIN_SETTING *s, htable_t *dict);

static void _main_conf_set_setting(S_MAIN_SETTING *s, htable_t *dict)
{
	int i;
	int ret = 0;
	long val_int = 0;
	char *val_str = NULL;
	dlib_conf_t *n = NULL;
	
	for (i = 0; i < CONF_MAIN_ARGS_NUM; i++) {
		n = main_table + i;
		
		switch (n->str_table.index) {
		case MAIN_MAX_FD:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->max_fds = (uint32_t)n->int_table.defval;
				break;
			} 
			
			s->max_fds = (uint32_t)val_int;
			break;
			
		case MAIN_MAX_THREADS:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->max_threads = (uint32_t)n->int_table.defval;
				break;
			}
			
			s->max_threads = (uint32_t)val_int;
			break;
			
		case MAIN_CONF_PATH:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->conf_path = n->str_table.defval;
				break;
			}
			
			s->conf_path = val_str;
			break;
			
		case MAIN_LOG_PATH:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->log_path = n->str_table.defval;
				break;
			}
			
			s->log_path = val_str;
			break;
			
		case MAIN_MONT_HOST:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->mont_host = n->str_table.defval;
				break;
			}
			
			s->mont_host = val_str;
			break;
			
		case MAIN_MONT_PORT:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mont_port = (uint16_t)n->int_table.defval;
				break;
			}
			
			s->mont_port = (uint16_t)val_int;
			break;
			
		case MAIN_MONT_TIMEOUT:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mont_timeout = (uint16_t)n->int_table.defval;
				break;
			}
			
			s->mont_timeout = (uint16_t)val_int;
			break;
			
		case MAIN_MONT_RETRY:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mont_retry = (uint16_t)n->int_table.defval;
				break;
			}
			
			s->mont_retry = (uint16_t)val_int;
			break;
			
		case MAIN_MONT_PRIORITY:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mont_priority = 
					(uint16_t)n->int_table.defval;
				break;
			}
			
			s->mont_priority = (uint16_t)val_int;
			break;
			
		case MAIN_DCOMM_CONF:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->dcomm_conf = n->str_table.defval;
				break;
			}
			
			s->dcomm_conf = val_str;
			break;
			
		case MAIN_PROTOCOLS:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->protocols = n->str_table.defval;
				break;
			}
			
			s->protocols = val_str;
			break;
			
		case MAIN_TRANSACTION:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				if (strncmp(n->str_table.defval, "on", 2) == 0)
				{
					s->transaction = 1;
				} else {
					s->transaction = 0;
				}
				break;
			}
			
			if (strncmp(val_str, "on", 2) == 0) {
				s->transaction = 1;
			} else {
				s->transaction = 0;
			}
			dfree(val_str);
			break;
			
		case MAIN_BINLOG_PATH:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->binlog_path = n->str_table.defval;
				break;
			}
			
			s->binlog_path = val_str;
			break;
			
		case MAIN_MF_PATH:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->mf_path = n->str_table.defval;
				break;
			}
			
			s->mf_path = val_str;
			break;
			
		case MAIN_MF_CACHE_SIZE:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mf_cache_size = (uint32_t)n->int_table.defval;
				break;
			}
			
			s->mf_cache_size = (uint32_t)val_int;
			break;
			
		case MAIN_MF_PAGE_SIZE:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->mf_page_size = (uint32_t)n->int_table.defval;
				break;
			}
			
			s->mf_page_size = (uint32_t)val_int;
			break;
			
		case MAIN_FACTORY_PATH:
			val_str = dlib_conf_get_string(dict, n->str_table.name,
						  CONF_STR_MOVE);
			if (val_str == NULL) {
				s->factory_path = n->str_table.defval;
				break;
			}
			
			s->factory_path = val_str;
			break;
			
		case MAIN_STRIPE_SIZE:
			ret = dlib_conf_get_integer(dict, n->int_table.name,
					       &val_int);
			if (ret < 0) {
				s->stripe_size = (uint32_t)n->int_table.defval;
				break;
			}
			
			s->stripe_size = (uint32_t)val_int;
			break;
			
		default:
			break;
		}/* end switch */
	}/* end for */
	
	return;
}

static void _main_conf_dump(const S_MAIN_SETTING *s);

static void _main_conf_dump(const S_MAIN_SETTING *s)
{
	fprintf(stdout, "%s version %s Main Setting Arguments:\n"
		"    conf_file		: %s\n"
		"    max_fds 		: %u\n"
		"    max_threads	: %u\n"
		"    conf_path		: %s\n"
		"    log_path		: %s\n"
		"    mont_host		: %s\n"
		"    mont_port		: %hu\n"
		"    mont_timeout	: %hu\n"
		"    mont_retry		: %hu\n"
		"    mont_priority	: %hu\n"
		"    dcomm_conf		: %s\n"
		"    protocols		: %s\n"
		"    transaction	: %u\n"
		"    binlog_path	: %s\n"
		"    mf_path		: %s\n"
		"    mf_cache_size	: %u\n"
		"    mf_page_size	: %u\n"
		"    factory_path	: %s\n"
		"    stripe_size	: %u\n\n",
		"test_conf", "0.1.0",
		s->conf_file, s->max_fds, s->max_threads, s->conf_path,
		s->log_path, s->mont_host, s->mont_port, s->mont_timeout,
		s->mont_retry, s->mont_priority, s->dcomm_conf, s->protocols,
		s->transaction, s->binlog_path, s->mf_path, s->mf_cache_size,
		s->mf_page_size, s->factory_path, s->stripe_size);
	fflush(stdout);

	return;
}

int main(int argc, char *argv[])
{
	htable_t *dict = NULL;
	S_MAIN_SETTING s;
	char *cfile = CONF_FILE;
	
	if (argc > 1)
		cfile = argv[1];
	
	s.conf_file = cfile;
	
	dict = dlib_conf_init(cfile, main_table, CONF_MAIN_ARGS_NUM,
			 CONF_MAIN_DICT_LEN);
	if (dict == NULL) {
		fprintf(stderr, "CONF: dlib_conf_init error, unexpected.\n");
		return -1;
	}
	_main_conf_set_setting(&s, dict);

	dlib_conf_exit(dict);
	
	_main_conf_dump(&s);
	
	if (s.conf_path != (char *)&DEF_CONF_PATH)
		dfree(s.conf_path);
	if (s.log_path != (char *)&DEF_LOG_PATH)
		dfree(s.log_path);
	if (s.mont_host != (char *)&DEF_MONT_HOST)
		dfree(s.mont_host);
	if (s.dcomm_conf != (char *)&DEF_DCOMM_CONF)
		dfree(s.dcomm_conf);
	if (s.protocols != (char *)&DEF_PROTOCOLS)
		dfree(s.protocols);
	if (s.binlog_path != (char *)&DEF_BINLOG_PATH)
		dfree(s.binlog_path);
	if (s.mf_path != (char *)&DEF_MF_PATH)
		dfree(s.mf_path);
	if (s.factory_path != (char *)&DEF_FACTORY_PATH)
		dfree(s.factory_path);

	return 0;
}
